#include"VKGraphics.h"
#include<vector>
#include<iostream>
#include<set>
#include<string>
#include<fstream>
#include<chrono>
#include<glm/gtc/matrix_transform.hpp>
using namespace VKG;
using namespace vk;
using namespace std;


 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT,
                                                    VkDebugReportObjectTypeEXT,
                                                    uint64_t,
                                                    size_t,
                                                    int32_t,
                                                    const char*,
                                                    const char* msg,
                                                    void*)
{
    std::cerr<<"validation layer: "<<msg<<endl;
    return VK_FALSE;
}

VKGraphics::VKGraphics(/* args */)
{
}

VKGraphics::~VKGraphics()
{
    distroy();
}



void VKG::VKGraphics::draw()
{
    drawFrame();
}

void VKG::VKGraphics::wait()
{
    device.waitIdle();
}

void VKG::VKGraphics::undateUBO()
{
    static auto start = chrono::high_resolution_clock::now();
    auto current = chrono::high_resolution_clock::now();
    float time = chrono::duration_cast<chrono::milliseconds>(current- start ).count()/1000.0f;
    ubo.model = glm::rotate(glm::mat4(1.0f),time*glm::radians(90.0f),glm::vec3(0.0f,0.0f,1.0f));
    ubo.view = glm::lookAt(glm::vec3(2.0f,2.0f,2.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,0.0f,1.0f));
    ubo.proj = glm::perspective(glm::radians(45.0f),swapExent.width/(float)swapExent.height,0.1f,10.0f);
    ubo.proj[1][1] *=-1;

    void* data = device.mapMemory(uniformBufferMemory,0,sizeof(ubo));
    memcpy(data,&ubo,sizeof(ubo));
    device.unmapMemory(uniformBufferMemory);

}

void VKG::VKGraphics::distroy()
{
    if (instance)
    {
        if (callback)
        {
           // instance.destroyDebugReportCallbackEXT(callback);
        }
       
        if (device)
        {
            if (swapImageViews.size()>0)
            {
                for(auto imageview : swapImageViews)
                {
                    device.destroyImageView(imageview);
                }
            }
            
            if (swapchain)
            {
                device.destroySwapchainKHR(swapchain);
            }
            if (renderPass)
            {
                device.destroyRenderPass(renderPass);
            }
            if(pipelineLayout)
            {
                device.destroyPipelineLayout(pipelineLayout);
            }
            if (graphicPipeline)
            {
                device.destroyPipeline(graphicPipeline);
            }
            if (swapchainFrameBuffers.size()>0)
            {
                for(auto &framebuffer:swapchainFrameBuffers){
                    device.destroyFramebuffer(framebuffer);
                }
            }
            if(commandpool)
            {
                device.destroyCommandPool(commandpool);
            }
            if(renderfinishedSemaphore)
            {
                device.destroySemaphore(renderfinishedSemaphore);
            }
            if (imageAvailableSemaphore)
            {
                device.destroySemaphore(imageAvailableSemaphore);
            }
            if (SyncObjects.size()>0)
            {
                for(auto & item:SyncObjects)
                {
                    item.destroy();
                }
            }
            if (vertexBuffer)
            {
                device.destroyBuffer(vertexBuffer);
            }
            
            if (vertexBufferMemory)
            {
                device.freeMemory(vertexBufferMemory);
            }

            if (indexBuffer)
            {
                device.destroyBuffer(indexBuffer);
            }
            
            if (indexBufferMemory)
            {
                device.freeMemory(indexBufferMemory);
            }
            if(descriptorLayout)
            {
                device.destroyDescriptorSetLayout(descriptorLayout);
            }
            
            if (uniformBuffer)
            {
                device.destroyBuffer(uniformBuffer);
            }
            
            if (uniformBufferMemory)
            {
                device.freeMemory(uniformBufferMemory);
            }
         
            
            if(descirptorPool)
            {
    
                device.destroyDescriptorPool(descirptorPool);
            }
            device.destroy();
        }
         if (surface)
            instance.destroySurfaceKHR(surface);
        instance.destroy();
    }
    
}

void VKG::VKGraphics::CreateInstance()
{
    vk::ApplicationInfo appinfo;
    appinfo.setApiVersion(VK_API_VERSION_1_3)
        .setPEngineName("no egnine")
        .setPApplicationName("no egnine")
        .setEngineVersion(VK_MAKE_VERSION(1,0,0))
        .setApplicationVersion(VK_MAKE_VERSION(1, 0, 0));


    vk::InstanceCreateInfo instanceInfo ;

    auto extends = getRequiredExtensions();

    instanceInfo.setPApplicationInfo(&appinfo)
        .setPEnabledExtensionNames(extends);

    if (enableValidationLayers&&checkValidationLayersSupport())
    {
        instanceInfo.setPEnabledLayerNames(validationLayers);
    }
       
    instance = vk::createInstance(instanceInfo);
}

void VKG::VKGraphics::setupDebugCallback()
{
    // if(!enableValidationLayers)
    //     return;
    // vk::DebugReportCallbackCreateInfoEXT info ;
    // info.setPfnCallback(debugCallback);
    
    // callback  = instance.createDebugReportCallbackEXT(info);
    
}

void VKG::VKGraphics::pickPhysicalDevice()
{
    auto physicalDevices = instance.enumeratePhysicalDevices();
    if (physicalDevices.size() == 0)
    {
        cerr<<"failed to find gpus with vulkan support!"<<endl;
        return;
    }
    for(auto device:physicalDevices){
        if (isDeviceSuitable(device))
        {
            physicaldevice = device;
            return;
        }
        
    }
    if (!physicaldevice)
    {
        throw std::runtime_error("failed to find a suitable GPU!");
    }
}

void VKG::VKGraphics::createLogicDevice()
{
    QueueFamilyIndices indices = findQueueFamilies(physicaldevice);
    set<int> uniqueQueuefamilies = {indices.graphicsFamily,indices.presentFamily};
    vector<DeviceQueueCreateInfo> queueinfos ;
    float priorities =1.0f;
    for(int indices :uniqueQueuefamilies){
        vk::DeviceQueueCreateInfo queueinfo;
        queueinfo.setQueueFamilyIndex(indices) 
                .setQueueCount(1)
                .setQueuePriorities(priorities);
        queueinfos.push_back(queueinfo);
    }
    

    vk::PhysicalDeviceFeatures devicefeatures = {};

    vk::DeviceCreateInfo info;
    info.setQueueCreateInfos(queueinfos)
        .setPEnabledExtensionNames(deviceExtensions)
        .setPEnabledFeatures(&devicefeatures);
        
    if (enableValidationLayers)
    {
        info.setPEnabledLayerNames(validationLayers);
    }
    

    device = physicaldevice.createDevice(info);
    graphicsQueure =  device.getQueue(indices.graphicsFamily,0);
    presentQueue = device.getQueue(indices.presentFamily,0);
}

void VKG::VKGraphics::createSwapChain()
{
    if (!device)
    {
         throw runtime_error("调用createSwapChain之前请先创建device");
    }
    
    SwapChainSupportDetails supportDetails = querySwapchainSupport(physicaldevice);
    swapExent = supportDetails.chooseSwapExtent(0,0);
    swapformat = supportDetails.chooseFormat();
    PresentModeKHR persentMode = supportDetails.choosePresentMode();

    uint32_t imageCount = supportDetails.capabilities.minImageCount +1;
    if (supportDetails.capabilities.maxImageCount>0&& supportDetails.capabilities.maxImageCount<imageCount)
    {
        imageCount = supportDetails.capabilities.maxImageCount;
    }
    
    SwapchainCreateInfoKHR info ;
    info.setSurface(surface)
        .setImageExtent(swapExent)
        .setImageFormat(swapformat.format)
        .setImageColorSpace(swapformat.colorSpace)
        .setPresentMode(persentMode)
        .setMinImageCount (imageCount)
        .setImageArrayLayers(1)
        .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment);
    auto queueIndices = findQueueFamilies(physicaldevice);
    auto indices = {(uint32_t)queueIndices.graphicsFamily,(uint32_t)queueIndices.presentFamily};
    if (queueIndices.graphicsFamily!= queueIndices.presentFamily)
    {
       info.setQueueFamilyIndices(indices)
            .setQueueFamilyIndexCount(2)
            .setImageSharingMode(vk::SharingMode::eConcurrent);
     
    }else  {
         info.setImageSharingMode(vk::SharingMode::eExclusive);
    }
    info.setPreTransform(supportDetails.capabilities.currentTransform)
        .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
        .setClipped(VK_TRUE)
        .setOldSwapchain(VK_NULL_HANDLE);
    
    swapchain  = device.createSwapchainKHR(info);

    swapchainImages = device.getSwapchainImagesKHR(swapchain);

    cout<< "swapchainImages size"<<swapchainImages.size()<<endl;

}

void VKG::VKGraphics::createImageViews()
{
    vk::ComponentMapping mapping;
    mapping.setA(vk::ComponentSwizzle::eIdentity)
           .setB(vk::ComponentSwizzle::eIdentity)
           .setB(vk::ComponentSwizzle::eIdentity)
           .setB(vk::ComponentSwizzle::eIdentity);
    vk::ImageSubresourceRange range;
    range.setLayerCount(1)
         .setLevelCount(1)
         .setBaseArrayLayer(0)
         .setBaseMipLevel(0)
         .setAspectMask(vk::ImageAspectFlagBits::eColor);
    for(const auto& image:swapchainImages){

        vk::ImageViewCreateInfo info;
        info.setImage(image)
            .setViewType(vk::ImageViewType::e2D)
            .setFormat(swapformat.format)
            .setComponents(mapping)
            .setSubresourceRange(range);
        auto imageview = device.createImageView(info);

        swapImageViews.push_back(imageview);

    }
}

void VKG::VKGraphics::createRanderpass()
{
    //附件
    vk::AttachmentDescription colorattch;
    colorattch.setFormat(swapformat.format)
              .setLoadOp(vk::AttachmentLoadOp::eClear)
              .setStoreOp(vk::AttachmentStoreOp::eDontCare)
              .setSamples(vk::SampleCountFlagBits::e1)
              .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
              .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
              .setInitialLayout(vk::ImageLayout::eUndefined)
              .setFinalLayout(vk::ImageLayout::ePresentSrcKHR);
    // 子通道
    vk::AttachmentReference colorref;
    colorref.setAttachment(0)
            .setLayout(vk::ImageLayout::eColorAttachmentOptimal);
    vk::SubpassDescription subpass;
    subpass.setPipelineBindPoint(PipelineBindPoint::eGraphics)
           .setColorAttachments(colorref); 

    vk::RenderPassCreateInfo info ;
    info .setAttachments(colorattch)
         .setSubpasses(subpass);
    SubpassDependency subpassDependency;
    subpassDependency.setSrcSubpass(VK_SUBPASS_EXTERNAL)
                    .setDstSubpass(0)
                    .setSrcStageMask(PipelineStageFlagBits::eColorAttachmentOutput)
                    .setSrcAccessMask(AccessFlagBits::eNone)
                    .setDstStageMask(PipelineStageFlagBits::eColorAttachmentOutput)
                    .setDstAccessMask(AccessFlagBits::eColorAttachmentRead|AccessFlagBits::eColorAttachmentWrite);
    info.setDependencies(subpassDependency);
    renderPass = device.createRenderPass(info);

}

void VKG::VKGraphics::createGraphicsPipline()
{
    //着色器
    auto fragModule = createShaderModule("./frag.spv");
    auto vertModule = createShaderModule("./vert.spv");
    vk::PipelineShaderStageCreateInfo fragInfo;
    fragInfo.setModule(fragModule)
        .setPName("main")
        .setStage(vk::ShaderStageFlagBits::eFragment);
    vk::PipelineShaderStageCreateInfo vertInfo;
    vertInfo.setStage(vk::ShaderStageFlagBits::eVertex)
            .setModule(vertModule)
            .setPName("main");
    vector<PipelineShaderStageCreateInfo> stageInfos = {fragInfo,vertInfo};
    //顶点输入
    PipelineVertexInputStateCreateInfo vertexInfo;
    Vertex vert;
    auto inputBind = vert.getBindDescription();
    auto inputAttr= vert.getAttrDescription();
    vertexInfo.setVertexAttributeDescriptions(inputAttr)
    .setVertexBindingDescriptions(inputBind);
    
    // 输入组件
    PipelineInputAssemblyStateCreateInfo inputInfo;
    inputInfo.setTopology(PrimitiveTopology::eTriangleList) //三角形
             .setPrimitiveRestartEnable(false);
    //视口
    Viewport viewport;
    viewport.setX(0).setY(0)
            .setHeight(swapExent.height)
            .setWidth(swapExent.width)
            .setMaxDepth(1)
            .setMinDepth(0);
    //裁切
    Rect2D scissor;
    scissor.setOffset({0,0})
            .setExtent(swapExent);
    //视口与裁切
    PipelineViewportStateCreateInfo viewportInfo;
    viewportInfo.setViewports(viewport)
                .setScissors(scissor);
    
    //光栅化
    PipelineRasterizationStateCreateInfo rasterizer;
    rasterizer.setDepthClampEnable(false) //超出视口空间部分是否收敛，需要显卡支持
              .setRasterizerDiscardEnable(false) //是否丢弃光栅化
              .setPolygonMode(PolygonMode::eFill) //多边形光栅化模式
              .setLineWidth(1.0f)
              .setCullMode(CullModeFlagBits::eNone)
              .setFrontFace(FrontFace::eClockwise)
              // 这部分是设置参数来更改深度值 。 通常用来做阴影贴图 
              .setDepthBiasEnable(false)
              .setDepthBiasClamp(0)
              .setDepthBiasConstantFactor(0)
              .setDepthBiasSlopeFactor(0);
    //多重采样
    PipelineMultisampleStateCreateInfo multisampleInfo;
    multisampleInfo.setSampleShadingEnable(false)
                   .setRasterizationSamples(SampleCountFlagBits::e1)
                   .setMinSampleShading(1.0f)
                   .setPSampleMask(nullptr)
                   .setAlphaToCoverageEnable(false)
                   .setAlphaToOneEnable(false);
    //深度和模板测试  .暂时用不着  赋值为null;
    PipelineDepthStencilStateCreateInfo *depthStencilInfo = nullptr;
    //颜色混合  两种方式二选一：VkPipelineColorBlendAttachmentState ；VkPipelineColorBlendStateCreateInfo
    PipelineColorBlendAttachmentState colorblendstate;
    colorblendstate.setColorWriteMask(ColorComponentFlagBits::eA|ColorComponentFlagBits::eB|ColorComponentFlagBits::eG|ColorComponentFlagBits::eR)
                   .setBlendEnable(false)
                   .setColorBlendOp(BlendOp::eAdd)
                   .setAlphaBlendOp(BlendOp::eAdd)
                   .setDstAlphaBlendFactor(BlendFactor::eZero)
                   .setDstColorBlendFactor(BlendFactor::eZero)
                   .setSrcAlphaBlendFactor(BlendFactor::eOne)
                   .setSrcColorBlendFactor(BlendFactor::eOne);
    PipelineColorBlendStateCreateInfo colorblendstateInfo;
    colorblendstateInfo.setAttachments(colorblendstate)
                        .setLogicOpEnable(false)
                        .setLogicOp(LogicOp::eCopy)
                        .setBlendConstants({0.0,0.0,0.0,0.0});
    //动态修改
    vector<DynamicState>  dynamicsctates = {DynamicState::eViewport,DynamicState::eLineWidth};
    PipelineDynamicStateCreateInfo dynamicInfo;
    dynamicInfo.setDynamicStates(dynamicsctates);

    //管道布局
    PipelineLayoutCreateInfo layoutinfo;
    layoutinfo.setSetLayouts(descriptorLayout)
                .setPushConstantRanges(nullptr);
    pipelineLayout = device.createPipelineLayout(layoutinfo);
    
    //---------------------------------------创建管道  ----------------------------------------------------
    GraphicsPipelineCreateInfo pipelineInfo;
    pipelineInfo.setStages(stageInfos)
                .setRenderPass(renderPass)
                .setPVertexInputState(&vertexInfo)
                .setPInputAssemblyState(&inputInfo)
                .setPViewportState(&viewportInfo)
                .setPMultisampleState(&multisampleInfo)
                .setPRasterizationState(&rasterizer)
                .setPColorBlendState(&colorblendstateInfo)
                .setPDepthStencilState(depthStencilInfo)
                //.setPDynamicState(&dynamicInfo)
                .setLayout(pipelineLayout)
                .setSubpass(0)
                .setBasePipelineHandle(VK_NULL_HANDLE)
                .setBasePipelineIndex(-1);

    graphicPipeline = device.createGraphicsPipeline(VK_NULL_HANDLE,pipelineInfo).value;
    if (!graphicPipeline)
    {
        throw runtime_error("创建图形管道失败");
    }
    device.destroyShaderModule(fragModule);
    device.destroyShaderModule(vertModule);
}

void VKG::VKGraphics::createSwapchainFrameBuffers()
{
    for(auto &imageview :swapImageViews){

        FramebufferCreateInfo info ;
        info.setRenderPass(renderPass)
            .setAttachments(imageview)
            .setWidth(swapExent.width)
            .setHeight(swapExent.height)
            .setLayers(1);
        auto framebuffer = device.createFramebuffer(info);
        swapchainFrameBuffers.push_back(framebuffer);
    }
}

void VKG::VKGraphics::createCommandPool()
{
    auto indices = findQueueFamilies(physicaldevice);
    CommandPoolCreateInfo info ;
    info.setQueueFamilyIndex(indices.graphicsFamily)
        .setFlags(CommandPoolCreateFlagBits::eResetCommandBuffer);
    commandpool = device.createCommandPool(info);
    if (!commandpool)
    {
        throw runtime_error("create command pool faild!");
    }
}

void VKG::VKGraphics::createCommandBuffers()
{
    CommandBufferAllocateInfo allocateInfo;
    allocateInfo.setCommandPool(commandpool)
                .setCommandBufferCount(swapchainFrameBuffers.size())
                //.setCommandBufferCount(1)
                .setLevel(CommandBufferLevel::ePrimary);

    commandBuffers = device.allocateCommandBuffers(allocateInfo);
   
//    recordCommandBuffer(commandBuffers[0],0);
//    recordCommandBuffer(commandBuffers[1],1);
    int i=0;
    for(auto commandBuffer:commandBuffers)
    {
        CommandBufferBeginInfo commandbegininfo;
        commandbegininfo.setFlags(CommandBufferUsageFlagBits::eSimultaneousUse);
                        
        commandBuffer.begin(commandbegininfo);
        RenderPassBeginInfo renderinfo;
        Rect2D area;
        area.setOffset({0,0})
            .setExtent(swapExent);
        ClearValue clear ;
        ClearColorValue f;
        f.setFloat32({0.0f,0.0f,0.0f,1.0f});
        clear.setColor(f);
        renderinfo.setRenderPass(renderPass)
                  .setFramebuffer(swapchainFrameBuffers[i])
                  .setRenderArea(area)
                  .setClearValues(clear);
        i++;
        commandBuffer.beginRenderPass(renderinfo,SubpassContents::eInline);
        commandBuffer.bindPipeline(PipelineBindPoint::eGraphics,graphicPipeline);
        commandBuffer.bindVertexBuffers(0,vertexBuffer,{0});
        commandBuffer.bindIndexBuffer(indexBuffer,{0},IndexType::eUint16);
        commandBuffer.bindDescriptorSets(PipelineBindPoint::eGraphics,pipelineLayout,0,descriptorset,nullptr);

        //commandBuffer.bindDescriptorSets();
        cout<<"draw triangle"<<endl;
       // commandBuffer.draw(3,1,0,0);
        //commandBuffer.draw(static_cast<uint32_t>(verteces.size()),1,0,0);
        commandBuffer.drawIndexed(indices.size(),1,0,0,0);
        commandBuffer.endRenderPass();
        commandBuffer.end();
    }
}

void VKG::VKGraphics::createSemaphores()
{

    for (size_t i = 0; i < swapImageViews.size(); i++)
    {
        SyncObjects.push_back(SyncObject(device));
    }
    
}
uint32_t currframe = 0;
void VKG::VKGraphics::drawFrame()
{
    auto syncOb =SyncObjects[currframe];
    device.waitForFences(syncOb.fence,true,UINT64_MAX);
    device.resetFences(syncOb.fence);

    uint32_t imageindex = device.acquireNextImageKHR(swapchain,numeric_limits<int64_t>::max(),syncOb.imageAvailableSemaphore,VK_NULL_HANDLE).value;
    auto commandBuffer = commandBuffers[currframe];
    SubmitInfo subinfo;
    vector<PipelineStageFlags> stageflag ={PipelineStageFlagBits::eTopOfPipe} ;
    subinfo.setWaitSemaphores(syncOb.imageAvailableSemaphore)
            .setWaitDstStageMask(stageflag)
            .setCommandBuffers(commandBuffer)
            .setSignalSemaphores(syncOb.renderFinishedSemaphore);
    graphicsQueure.submit(subinfo,syncOb.fence);
    PresentInfoKHR presentinfo;

    presentinfo.setWaitSemaphores(syncOb.renderFinishedSemaphore)
                .setSwapchains(swapchain)
                .setImageIndices(imageindex);
    presentQueue.presentKHR(presentinfo);
    currframe = (currframe+1)%swapImageViews.size();
}

void VKG::VKGraphics::recordCommandBuffer(CommandBuffer commandBuffer,int32_t imageindex)
{
        CommandBufferBeginInfo commandbegininfo;
        commandbegininfo.setFlags(CommandBufferUsageFlagBits::eSimultaneousUse);
        commandBuffer.begin(commandbegininfo);
        RenderPassBeginInfo renderinfo;
        Rect2D area;
        area.setOffset({0,0})
            .setExtent(swapExent);
        ClearValue clear ;
        ClearColorValue f;
        f.setFloat32({0.0f,0.0f,0.0f,1.0f});
        clear.setColor(f);
        renderinfo.setRenderPass(renderPass)
                  .setFramebuffer(swapchainFrameBuffers[imageindex])
                  .setRenderArea(area)
                  .setClearValues(clear);
     
        commandBuffer.beginRenderPass(renderinfo,SubpassContents::eInline);
        commandBuffer.bindPipeline(PipelineBindPoint::eGraphics,graphicPipeline);
        //cout<<"draw triangle"<<endl;
        commandBuffer.draw(3,1,0,0);

        commandBuffer.endRenderPass();
        commandBuffer.end();
}

void VKG::VKGraphics::createVertexBuffer()
{
    DeviceSize datasize = sizeof(verteces[0])*verteces.size();
    auto src = verteces.data();
    vertexBuffer = transBuffer(src,datasize,BufferUsageFlagBits::eVertexBuffer,vertexBufferMemory);

}

void VKG::VKGraphics::createIndexBuffer()
{
    DeviceSize datasize = sizeof(indices[0])*indices.size();
     auto src = indices.data();
    indexBuffer = transBuffer(src,datasize,BufferUsageFlagBits::eIndexBuffer,indexBufferMemory);
}

void VKG::VKGraphics::createDescriptorSetLayout()
{
    DescriptorSetLayoutBinding binding;
    binding.setBinding(0)
    .setStageFlags(ShaderStageFlagBits::eVertex)
    .setDescriptorType(DescriptorType::eUniformBuffer)
    .setDescriptorCount(1);
    DescriptorSetLayoutCreateInfo createinfo;
    createinfo.setBindings(binding);

    descriptorLayout = device.createDescriptorSetLayout(createinfo);
    createUinformBuffer();
}

void VKG::VKGraphics::createUinformBuffer()
{
    DeviceSize datasize = sizeof(ubo);
    uniformBuffer =  createBuffer(datasize,BufferUsageFlagBits::eUniformBuffer,MemoryPropertyFlagBits::eHostVisible|MemoryPropertyFlagBits::eHostCoherent,uniformBufferMemory);
}

void VKG::VKGraphics::createDescriptorSet()
{
    //描述符池
    DescriptorPoolSize poolsize;
    poolsize.setDescriptorCount(1)
    .setType(DescriptorType::eUniformBuffer);
    DescriptorPoolCreateInfo info;
    info.setPoolSizes(poolsize)
    .setMaxSets(1);

    descirptorPool  = device.createDescriptorPool(info); //描述符池
    //描述符集合
    DescriptorSetAllocateInfo setallocateinfo;
    setallocateinfo.setDescriptorPool(descirptorPool)
    .setDescriptorSetCount(1)
    .setSetLayouts(descriptorLayout);
    auto descriptorsets = device.allocateDescriptorSets(setallocateinfo); //描述符集合
    descriptorset = descriptorsets[0];
    //引用缓冲区
    DescriptorBufferInfo bufferinfo;
    bufferinfo.setBuffer(uniformBuffer)
    .setOffset(0)
    .setRange(sizeof(ubo));
    WriteDescriptorSet writor;
    writor.setBufferInfo(bufferinfo)
    .setDescriptorCount(1)
    .setDescriptorType(DescriptorType::eUniformBuffer)
    .setDstSet(descriptorset)
    .setDstBinding(0)
    .setDstArrayElement(0);
    device.updateDescriptorSets(writor,nullptr);
    
}

bool VKG::VKGraphics::checkValidationLayersSupport()
{ 
    vector<LayerProperties> layers =  enumerateInstanceLayerProperties();
    for (auto validation: validationLayers)
    {
        for(auto item :layers){
           // cout<<item.layerName<<endl;
            if(strcmp(validation,item.layerName)==0)
                return true;
        }   
    }
    
    
    return false;
}

bool VKG::VKGraphics::checkDeviceExtensionSupport(vk::PhysicalDevice device)
{
    auto  availableExtensions =  device.enumerateDeviceExtensionProperties();


    set<string> requiredExtensions (deviceExtensions.begin(),deviceExtensions.end());

    for(const auto& extension:availableExtensions)
    {
        const char* name = extension.extensionName;
        // std::cout<<"strstr:"<<name<<"->"<< (string(name) == string("VK_KHR_swapchain")) <<endl;
       
        requiredExtensions.erase( string(name)) ;
    }

    return requiredExtensions.empty();
}

bool VKG::VKGraphics::isDeviceSuitable(vk::PhysicalDevice device)
{
    auto indices = findQueueFamilies(device);
    auto extensionSupported = checkDeviceExtensionSupport(device);
    bool swapchainAdequate = false;
    if (extensionSupported)
    {
        SwapChainSupportDetails swapchainsupport = querySwapchainSupport(device);
        swapchainAdequate = !swapchainsupport.formates.empty()&&!swapchainsupport.presentModes.empty();
    }
    
    return indices.inComplete()&&extensionSupported&&swapchainAdequate;
}

SwapChainSupportDetails VKG::VKGraphics::querySwapchainSupport(vk::PhysicalDevice device)
{
     if (!surface){
        throw runtime_error("调用querySwapchainSupport之前请先创建surface");
    }
    SwapChainSupportDetails swapchainSupport;
    swapchainSupport.capabilities =  device.getSurfaceCapabilitiesKHR(surface);
    swapchainSupport.formates = device.getSurfaceFormatsKHR(surface);
    swapchainSupport.presentModes = device.getSurfacePresentModesKHR(surface);

    return swapchainSupport;
}

QueueFamilyIndices VKG::VKGraphics::findQueueFamilies(vk::PhysicalDevice device)
{
    if (!surface){
        throw runtime_error("调用findQueueFamilies之前请先创建surface");
    }
    QueueFamilyIndices indices;
    auto queuefamilies =  device.getQueueFamilyProperties();
    int i = 0;
    for(auto queue : queuefamilies){
       
        if (queue.queueCount>0 && queue.queueFlags&QueueFlagBits::eGraphics)
        {
            indices.graphicsFamily = i;
        }
        if (queue.queueCount>0)
        {
             auto presentFamily  = device.getSurfaceSupportKHR(i,surface);
             if (presentFamily)
             {
                indices.presentFamily =i;
             }
             
        }
        i++;
    }

    return indices;
}

std::vector<const char *> VKG::VKGraphics::getRequiredExtensions()
{
    if (enableValidationLayers)
    {
        _externs.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
    }
    
    return _externs;
}

std::vector<char> VKG::VKGraphics::readFile(const std::string &path)
{
    ifstream file(path,ios::binary|ios::ate);
    if(!file.is_open())
    {
        throw runtime_error("open file field!");
    }
    size_t len  = (size_t)file.tellg();

    vector<char> code(len);

    file.seekg(0);

    file.read(code.data(),len);
    file.close();
    return code;

}

vk::ShaderModule VKG::VKGraphics::createShaderModule(const std::string &path)
{
    auto buffer = readFile(path);
    vk::ShaderModuleCreateInfo info;
    auto code = reinterpret_cast<const uint32_t*>(buffer.data());
    info.setPCode(code)
        .setCodeSize(buffer.size());
    return device.createShaderModule(info);
}

uint32_t VKG::VKGraphics::findMemoryType(uint32_t typefilter, vk::MemoryPropertyFlags properties)
{
    auto deviceMemoryProperties = physicaldevice.getMemoryProperties();

    for (size_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++)
    {
        if((typefilter&(1<<i)) && ((deviceMemoryProperties.memoryTypes[i].propertyFlags&properties )==properties))
            return i;
    }
    
    throw runtime_error("没有找到合适内存类型");
}

vk::Buffer VKG::VKGraphics::createBuffer(vk::DeviceSize dataSize, vk::BufferUsageFlags usages, vk::MemoryPropertyFlags memoryProperties, vk::DeviceMemory & memory)
{
    BufferCreateInfo bufferinfo;
    bufferinfo.setSize(dataSize)
    .setSharingMode(SharingMode::eExclusive)
    .setUsage(usages);
    auto buffer = device.createBuffer(bufferinfo);

    auto memoryRequire = device.getBufferMemoryRequirements(buffer);
    MemoryAllocateInfo memoryinfo ;
    memoryinfo.setAllocationSize(memoryRequire.size)
    .setMemoryTypeIndex(findMemoryType(memoryRequire.memoryTypeBits,memoryProperties));
    memory = device.allocateMemory(memoryinfo);
    device.bindBufferMemory(buffer,memory,0);
    return buffer;
}

void VKG::VKGraphics::copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize bufferSize)
{
    CommandBufferAllocateInfo commandinfo;
    commandinfo.setCommandPool(commandpool)
    .setLevel(CommandBufferLevel::ePrimary)
    .setCommandBufferCount(1);
    auto commandBuffers = device.allocateCommandBuffers(commandinfo);

    CommandBufferBeginInfo begininfo;
    begininfo.setFlags(CommandBufferUsageFlagBits::eOneTimeSubmit);
    auto commandBuffer = commandBuffers[0];
    commandBuffer.begin(begininfo);

    BufferCopy region;
    region.setDstOffset(0)
    .setSrcOffset(0)
    .setSize(bufferSize);
    commandBuffer.copyBuffer(srcBuffer,dstBuffer,region);
    commandBuffer.end();

    SubmitInfo submitInfo;

    submitInfo.setCommandBuffers(commandBuffer);
    graphicsQueure.submit(submitInfo);
    graphicsQueure.waitIdle();

    device.freeCommandBuffers(commandpool,commandBuffers);

}



vk::Buffer VKG::VKGraphics::transBuffer(const void *src, vk::DeviceSize dataSize, vk::BufferUsageFlags usages, vk::DeviceMemory &memory)
{
    DeviceMemory stagingMemory;
    auto stagingBuffer = createBuffer(dataSize,
                                        BufferUsageFlagBits::eTransferSrc,
                                        MemoryPropertyFlagBits::eHostVisible|MemoryPropertyFlagBits::eHostCoherent,
                                        stagingMemory);
    void*data = device.mapMemory(stagingMemory,0,dataSize);
    memcpy(data,src,(size_t)dataSize);
    device.unmapMemory(stagingMemory);

    auto buffer = createBuffer(dataSize,
                                usages|BufferUsageFlagBits::eTransferDst,
                                MemoryPropertyFlagBits::eDeviceLocal,
                                memory);

    copyBuffer(stagingBuffer,buffer,dataSize);

    device.destroyBuffer(stagingBuffer);
    device.freeMemory(stagingMemory);
    return buffer;
}
